var SHIFT_LEFT_32 = 4294967296, SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;

export default class Pbf {
  gA: Uint8Array;
  pos: number;
  type: number;
  length: number;

  static LA = 0;
  static PA = 1;
  static DA = 2;
  static RA = 5;
  constructor(t: Uint8Array) {
    this.gA = ArrayBuffer.isView && ArrayBuffer.isView(t) ? t : new Uint8Array(t || 0);
    this.pos = 0;
    this.type = 0;
    this.length = this.gA.length;
 }

  destroy() {
      this.gA = new Uint8Array(0)
  }
  nw(t: Function, e: any, r: number) {
      for (r = r || this.length; this.pos < r; ) {
          var n = this.ow()
            , i = n >> 3
            , a = this.pos;
          this.type = 7 & n,
          t(i, e, this),
          this.pos === a && this.wA(n)
      }
      return e
  }
  MA(t: Function, e: any) {
      return this.nw(t, e, this.ow() + this.pos)
  }
  jA() {
      var t = readUInt32(this.gA, this.pos);
      return this.pos += 4, t
  }
  AA() {
      var t = readInt32(this.gA, this.pos);
      return this.pos += 4,
      t
  }
  kA() {
      var t = readUInt32(this.gA, this.pos) + readUInt32(this.gA, this.pos + 4) * SHIFT_LEFT_32;
      return this.pos += 8,
      t
  }
  OA() {
      var t = readUInt32(this.gA, this.pos) + readInt32(this.gA, this.pos + 4) * SHIFT_LEFT_32;
      return this.pos += 8,
      t
  }
  pA() {
      var t = this.xA(this.gA, this.pos, 1, 23, 4);
      return this.pos += 4,
      t
  }
  yA() {
      var t = this.xA(this.gA, this.pos, 1, 52, 8);
      return this.pos += 8,
      t
  }
  ow(t?: boolean) {
      var e = this.gA
        , r = e[this.pos++]
        , n = 127 & r;
      return r < 128 ? n : (n |= (127 & (r = e[this.pos++])) << 7,
      r < 128 ? n : (n |= (127 & (r = e[this.pos++])) << 14,
      r < 128 ? n : (n |= (127 & (r = e[this.pos++])) << 21,
      r < 128 ? n : readVarintRemainder(n |= (15 & e[this.pos]) << 28, t, this))))
  }
  mA() {
      return this.ow(!0)
  }
  lA() {
      var t = this.ow();
      return t % 2 == 1 ? (t + 1) / -2 : t / 2
  }
  vw() {
      return Boolean(this.ow())
  }
  aw() {
      var t = this.ow() + this.pos
        , e = readUtf8(this.gA, this.pos, t);
      return this.pos = t,
      e
  }
  mw() {
      var t = this.ow() + this.pos
        , e = this.gA.subarray(this.pos, t);
      return this.pos = t,
      e
  }
  tw(t: number[], e: boolean) {
      var r = readPackedEnd(this);
      for (t = t || []; this.pos < r; )
          t.push(this.ow(e));
      return t
  }
  IA(t: number[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.lA());
      return t
  }
  TA(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.vw());
      return t
  }
  FA(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.pA());
      return t
  }
  _A(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.yA());
      return t
  }
  SA(t: number[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.jA());
      return t
  }
  CA(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.AA());
      return t
  }
  EA(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.kA());
      return t
  }
  NA(t: any[]) {
      var e = readPackedEnd(this);
      for (t = t || []; this.pos < e; )
          t.push(this.OA());
      return t
  }
  wA(t: number) {
    (t &= 7) === Pbf.LA || 
    (
        t === Pbf.DA ? this.pos = this.ow() + this.pos : 
        t === Pbf.RA ? this.pos += 4 : t === Pbf.PA ? this.pos += 8 : 
        console.log("Unimplemented type: " + t)
    )
  }
  UA(t: number, e: number) {
      this.BA(t << 3 | e)
  }
  zA(t: number) {
      for (var e, r = this.length || 16; r < this.pos + t; )
          r *= 2;
      r !== this.length && ((e = new Uint8Array(r)).set(this.gA),
      this.gA = e,
      this.length = r)
  }
  finish() {
      return this.length = this.pos,
      this.pos = 0,
      this.gA.subarray(0, this.length)
  }
  qA(t: number) {
      this.zA(4),
      writeInt32(this.gA, t, this.pos),
      this.pos += 4
  }
  WA(t: number) {
      this.zA(4),
      writeInt32(this.gA, t, this.pos),
      this.pos += 4
  }
  GA(t: number) {
      this.zA(8),
      writeInt32(this.gA, -1 & t, this.pos),
      writeInt32(this.gA, Math.floor(t * SHIFT_RIGHT_32), this.pos + 4),
      this.pos += 8
  }
  HA(t: number) {
      this.zA(8),
      writeInt32(this.gA, -1 & t, this.pos),
      writeInt32(this.gA, Math.floor(t * SHIFT_RIGHT_32), this.pos + 4),
      this.pos += 8
  }
  BA(t: number) {
      268435455 < (t = +t || 0) || t < 0 ? writeBigVarint(t, this) : (this.zA(4),
      this.gA[this.pos++] = 127 & t | (127 < t ? 128 : 0),
      t <= 127 || (this.gA[this.pos++] = 127 & (t >>>= 7) | (127 < t ? 128 : 0),
      t <= 127 || (this.gA[this.pos++] = 127 & (t >>>= 7) | (127 < t ? 128 : 0),
      t <= 127 || (this.gA[this.pos++] = t >>> 7 & 127))))
  }
  VA(t: number) {
      this.BA(t < 0 ? 2 * -t - 1 : 2 * t)
  }
  $A(t?: any) {
      this.BA(Boolean(t) ? 1 : 0)
  }
  YA(t: any) {
      t = String(t),
      this.zA(4 * t.length),
      this.pos++;
      var e = this.pos;
      this.pos = writeUtf8(this.gA, t, this.pos),
      128 <= (t = this.pos - e) && makeRoomForExtraLength(e, t, this),
      this.pos = e - 1,
      this.BA(t),
      this.pos += t
  }
  KA(t: any) {
      this.zA(4),
      this.XA(this.gA, t, this.pos, !0, 23, 4),
      this.pos += 4
  }
  JA(t: any) {
      this.zA(8),
      this.XA(this.gA, t, this.pos, !0, 52, 8),
      this.pos += 8
  }
  ZA(t: any[]) {
      var e = t.length;
      this.BA(e),
      this.zA(e);
      for (var r = 0; r < e; r++)
          this.gA[this.pos++] = t[r]
  }
  QA(t: Function, e: number) {
      this.pos++;
      var r = this.pos;
      t(e, this),
      128 <= (e = this.pos - r) && makeRoomForExtraLength(r, e, this),
      this.pos = r - 1,
      this.BA(e),
      this.pos += e
  }
  fw(t: number, e: Function, r: any) {
      this.UA(t, Pbf.DA),
      this.QA(e, r)
  }
  tk(t: number, e: any) {
      this.fw(t, writePackedVarint, e)
  }
  rk(t: number, e: any) {
      this.fw(t, writePackedSVarint, e)
  }
  nk(t: number, e: any) {
      this.fw(t, writePackedBoolean, e)
  }
  ik(t: number, e: any) {
      this.fw(t, writePackedFloat, e)
  }
  ek(t: number, e: any) {
      this.fw(t, writePackedDouble, e)
  }
  ak(t: number, e: any) {
      this.fw(t, writePackedFixed32, e)
  }
  uk(t: number, e: any) {
      this.fw(t, writePackedSFixed32, e)
  }
  sk(t: number, e: any) {
      this.fw(t, writePackedFixed64, e)
  }
  fk(t: number, e: any) {
      this.fw(t, writePackedSFixed64, e)
  }
  ww(t: number, e: any) {
      this.UA(t, Pbf.DA),
      this.ZA(e)
  }
  hk(t: number, e: any) {
      this.UA(t, Pbf.RA),
      this.qA(e)
  }
  ck(t: number, e: any) {
      this.UA(t, Pbf.RA),
      this.WA(e)
  }
  vk(t: number, e: any) {
      this.UA(t, Pbf.PA),
      this.GA(e)
  }
  lk(t: number, e: any) {
      this.UA(t, Pbf.PA),
      this.HA(e)
  }
  rw(t: number, e: any) {
      this.UA(t, Pbf.LA),
      this.BA(e)
  }
  dk(t: number, e: any) {
      this.UA(t, Pbf.LA),
      this.VA(e)
  }
  uw(t: number, e: any) {
      this.UA(t, Pbf.DA),
      this.YA(e)
  }
  bk(t: number, e: any) {
      this.UA(t, Pbf.RA),
      this.KA(e)
  }
  pk(t: number, e: any) {
      this.UA(t, Pbf.PA),
      this.JA(e)
  }
  hw(t: number, e: any) {
      this.rw(t, Boolean(e))
  }
  xA(t: Uint8Array, e: number, r: number, n: number, i: number) {
      var a, o, s = 8 * i - n - 1, u = (1 << s) - 1, c = u >> 1, f = -7, l = r ? i - 1 : 0, h = r ? -1 : 1, r = t[e + l];
      for (l += h,
      a = r & (1 << -f) - 1,
      r >>= -f,
      f += s; 0 < f; a = 256 * a + t[e + l],
      l += h,
      f -= 8)
          ;
      for (o = a & (1 << -f) - 1,
      a >>= -f,
      f += n; 0 < f; o = 256 * o + t[e + l],
      l += h,
      f -= 8)
          ;
      if (0 === a)
          a = 1 - c;
      else {
          if (a === u)
              return o ? NaN : 1 / 0 * (r ? -1 : 1);
          o += Math.pow(2, n),
          a -= c
      }
      return (r ? -1 : 1) * o * Math.pow(2, a - n)
  }
  XA(t: Uint8Array, e: any, r: number, n: any, i: number, a: number) {
      var o, s, u = 8 * a - i - 1, c = (1 << u) - 1, f = c >> 1, l = 23 === i ? Math.pow(2, -24) - Math.pow(2, -77) : 0, h = n ? 0 : a - 1, d = n ? 1 : -1, a = e < 0 || 0 === e && 1 / e < 0 ? 1 : 0;
      for (e = Math.abs(e),
      isNaN(e) || e === 1 / 0 ? (s = isNaN(e) ? 1 : 0,
      o = c) : (o = Math.floor(Math.log(e) / Math.LN2),
      e * (n = Math.pow(2, -o)) < 1 && (o--,
      n *= 2),
      2 <= (e += 1 <= o + f ? l / n : l * Math.pow(2, 1 - f)) * n && (o++,
      n /= 2),
      c <= o + f ? (s = 0,
      o = c) : 1 <= o + f ? (s = (e * n - 1) * Math.pow(2, i),
      o += f) : (s = e * Math.pow(2, f - 1) * Math.pow(2, i),
      o = 0)); 8 <= i; t[r + h] = 255 & s,
      h += d,
      s /= 256,
      i -= 8)
          ;
      for (o = o << i | s,
      u += i; 0 < u; t[r + h] = 255 & o,
      h += d,
      o /= 256,
      u -= 8)
          ;
      t[r + h - d] |= 128 * a
  }
}

function readVarintRemainder(t: number, e: boolean = false, r: any) {
    var n = r.gA
      , i = n[r.pos++]
      , a = (112 & i) >> 4;
    if (i < 128)
        return toNum(t, a, e);
    if (a |= (127 & (i = n[r.pos++])) << 3,
    i < 128)
        return toNum(t, a, e);
    if (a |= (127 & (i = n[r.pos++])) << 10,
    i < 128)
        return toNum(t, a, e);
    if (a |= (127 & (i = n[r.pos++])) << 17,
    i < 128)
        return toNum(t, a, e);
    if (a |= (127 & (i = n[r.pos++])) << 24,
    i < 128)
        return toNum(t, a, e);
    if (a |= (1 & (i = n[r.pos++])) << 31,
    i < 128)
        return toNum(t, a, e);
    throw new Error("Expected varint not more than 10 bytes")
}

function readPackedEnd(t: any) {
    return t.type === Pbf.DA ? t.ow() + t.pos : t.pos + 1
}
function toNum(t: number, e: number, r: boolean) {
    return r ? 4294967296 * e + (t >>> 0) : 4294967296 * (e >>> 0) + (t >>> 0)
}
function writeBigVarint(t: number, e: Pbf) {
    var r, n;
    if (0 <= t ? (r = t % 4294967296 | 0,
    n = t / 4294967296 | 0) : (n = ~(-t / 4294967296),
    4294967295 ^ (r = ~(-t % 4294967296)) ? r = r + 1 | 0 : n = n + 1 | (r = 0)),
    0x10000000000000000 <= t || t < -0x10000000000000000)
        throw new Error("Given varint doesn't fit into 10 bytes");
    e.zA(10),
    writeBigVarintLow(r, n, e),
    writeBigVarintHigh(n, e)
}
function writeBigVarintLow(t: number, e: any, r: Pbf) {
    r.gA[r.pos++] = 127 & t | 128,
    t >>>= 7,
    r.gA[r.pos++] = 127 & t | 128,
    t >>>= 7,
    r.gA[r.pos++] = 127 & t | 128,
    t >>>= 7,
    r.gA[r.pos++] = 127 & t | 128,
    r.gA[r.pos] = 127 & (t >>>= 7)
}
function writeBigVarintHigh(t: number, e: Pbf) {
    var r = (7 & t) << 4;
    e.gA[e.pos++] |= r | ((t >>>= 3) ? 128 : 0),
    t && (e.gA[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0),
    t && (e.gA[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0),
    t && (e.gA[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0),
    t && (e.gA[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0),
    t && (e.gA[e.pos++] = 127 & t)))))
}
function makeRoomForExtraLength(t: number, e: number, r: Pbf) {
    var n = e <= 16383 ? 1 : e <= 2097151 ? 2 : e <= 268435455 ? 3 : Math.ceil(Math.log(e) / (7 * Math.LN2));
    r.zA(n);
    for (var i = r.pos - 1; t <= i; i--)
        r.gA[i + n] = r.gA[i]
}
function writePackedVarint(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.BA(t[r])
}
function writePackedSVarint(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.VA(t[r])
}
function writePackedFloat(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.KA(t[r])
}
function writePackedDouble(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.JA(t[r])
}
function writePackedBoolean(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.$A(t[r])
}
function writePackedFixed32(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.qA(t[r])
}
function writePackedSFixed32(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.WA(t[r])
}
function writePackedFixed64(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.GA(t[r])
}
function writePackedSFixed64(t: any[], e: Pbf) {
    for (var r = 0; r < t.length; r++)
        e.HA(t[r])
}
function readUInt32(t: Uint8Array, e: number) {
    return (t[e] | t[e + 1] << 8 | t[e + 2] << 16) + 16777216 * t[e + 3]
}
function writeInt32(t: Uint8Array, e: number, r: number) {
    t[r] = e,
    t[r + 1] = e >>> 8,
    t[r + 2] = e >>> 16,
    t[r + 3] = e >>> 24
}
function readInt32(t: Uint8Array, e: number) {
    return (t[e] | t[e + 1] << 8 | t[e + 2] << 16) + (t[e + 3] << 24)
}
function readUtf8(t: Uint8Array, e: number, r: number) {
    for (var n = "", i = e; i < r; ) {
        var a = t[i]
          , o = null
          , s = 239 < a ? 4 : 223 < a ? 3 : 191 < a ? 2 : 1;
        if (r < i + s)
            break;
        var u, c = undefined, f = undefined;
        1 === s ? a < 128 && (o = a) : 2 === s ? 128 == (192 & (c = t[i + 1])) && (o = (31 & a) << 6 | 63 & c) <= 127 && (o = null) : 3 === s ? (c = t[i + 1],
        f = t[i + 2],
        128 == (192 & c) && 128 == (192 & f) && ((o = (15 & a) << 12 | (63 & c) << 6 | 63 & f) <= 2047 || 55296 <= o && o <= 57343) && (o = null)) : 4 === s && (c = t[i + 1],
        f = t[i + 2],
        u = t[i + 3],
        128 == (192 & c) && 128 == (192 & f) && 128 == (192 & u) && ((o = (15 & a) << 18 | (63 & c) << 12 | (63 & f) << 6 | 63 & u) <= 65535 || 1114112 <= o) && (o = null)),
        null === o ? (o = 65533,
        s = 1) : 65535 < o && (o -= 65536,
        n += String.fromCharCode(o >>> 10 & 1023 | 55296),
        o = 56320 | 1023 & o),
        n += String.fromCharCode(o),
        i += s
    }
    return n
}
function writeUtf8(t: Uint8Array, e: string, r: number) {
    for (var n = 0, i = undefined, a = undefined; n < e.length; n++) {
        if (55295 < (i = e.charCodeAt(n)) && i < 57344) {
            if (!a) {
                56319 < i || n + 1 === e.length ? (t[r++] = 239,
                t[r++] = 191,
                t[r++] = 189) : a = i;
                continue
            }
            if (i < 56320) {
                t[r++] = 239,
                t[r++] = 191,
                t[r++] = 189,
                a = i;
                continue
            }
            i = a - 55296 << 10 | i - 56320 | 65536,
            a = null
        } else
            a && (t[r++] = 239,
            t[r++] = 191,
            t[r++] = 189,
            a = null);
        i < 128 ? t[r++] = i : (i < 2048 ? t[r++] = i >> 6 | 192 : (i < 65536 ? t[r++] = i >> 12 | 224 : (t[r++] = i >> 18 | 240,
        t[r++] = i >> 12 & 63 | 128),
        t[r++] = i >> 6 & 63 | 128),
        t[r++] = 63 & i | 128)
    }
    return r
}